package com.example.springbootzklock.lock;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

import java.util.concurrent.CountDownLatch;

/**
 * @Description: zk 实现分布式锁 实现类
 * @Author: luzhiming
 * @CreateDate: 2019/9/25 9:00
 * @Version: 1.0
 */
public class ZkTemplateLockImpl extends AbstractTemplateLock {

    /**
     * zookeeper连接地址
     */
    private static final String IP_ADDRESS = "127.0.0.1:2181";

    /**
     * session超时时间
     */
    private static final int SESSION_OUTTIME = 5000;

    /**
     * 使用java并发包 信号量技术 控制zookeeper连接成功之后，开始创建节点，否则情况下等待
     */
    private static CountDownLatch countDownLatch = null;

    /**
     * 创建锁路径
     */
    private static final String LOCK_PATH = "/lockPath";
    /**
     * 创建 zk 连接
     */
    ZkClient zkClient = new ZkClient(IP_ADDRESS, SESSION_OUTTIME);

    @Override
    protected boolean tryLock() {
        //获取锁思路：多个 jvm 同时创建临时节点，只要谁能够创建成功，谁就能够拿到锁
        try {
            zkClient.createEphemeral(LOCK_PATH);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    protected void waitLock() {
        //1.使用事件监听 监听lockPath 节点，如果节点被移除 则可以重新获取锁
        zkClient.subscribeDataChanges(LOCK_PATH, new IZkDataListener() {
            @Override
            public void handleDataChange(String dataPath, Object data) throws Exception {

            }

            @Override
            public void handleDataDeleted(String dataPath) throws Exception {
                if (countDownLatch != null) {
                    //节点被删除计数器变为0
                    countDownLatch.countDown();
                }
            }
        });

        //2.使用 countDownLatch 进行等待
        if (countDownLatch == null) {
            countDownLatch = new CountDownLatch(1);
        }

        try {
            //如果计数器不为0  则进行等待
            countDownLatch.await();
        } catch (Exception e) {

        }

        //3.如果当前节点被删除的情况下，需要重新获取锁


    }

    /**
     * 释放锁
     */
    @Override
    protected void unLockImpl() {
        if (zkClient != null) {
            zkClient.close();
            System.out.println(Thread.currentThread().getName() + ",释放锁!");
        }
    }

}